﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace kripto2._1.operation
{
    class feistel
    {
        //jaringan feistel 7 putaran

        private static byte[][] roundkey = new byte[7][];

        public static byte[] feistelencrypt(byte[] text, byte[] key)
        //feistel untuk enkripsi
        {
            generateroundkey(key);

            int panjangBlok = key.Length;
            int setengahBlok = key.Length / 2;

            //initial permutation, left diisi genap, right diisi ganjil
            byte[] left = new byte[setengahBlok];
            byte[] right = new byte[setengahBlok];

            int iterator = 0;
            for (int i = 0; i < panjangBlok; i += 2)
            {
                left[iterator] = text[i];
                iterator++;
            }

            iterator = 0;
            for (int i = 1; i < panjangBlok; i += 2)
            {
                right[iterator] = text[i];
                iterator++;
            }

            //round
            for (int i = 0; i < 7; i++)
            {
                byte[] temp = new byte[left.Length];
                //temp diisi dengan left
                left.CopyTo(temp, 0);

                //operasikan
                left = encryptround(left, right, roundkey[i]);
                right = temp;
            }

            //inverse permutasi, gabungkan
            byte[] result = new byte[panjangBlok];


            for (int i = 0; i < setengahBlok; i++)
            {
                result[i] = left[i];
            }

            for (int i = 0; i < setengahBlok; i++)
            {
                result[setengahBlok + i] = right[i];
            }

            return result;
        }

        public static byte[] feisteldecrypt(byte[] text, byte[] key)
        //feistel untuk dekripsi
        {
            generateroundkey(key);

            int panjangBlok = key.Length;
            int setengahBlok = key.Length / 2;

            //initial permutation, pisahkan
            byte[] left = new byte[setengahBlok];
            byte[] right = new byte[setengahBlok];

            for (int i = 0; i < setengahBlok; i++)
            {
                left[i] = text[i];
            }

            for (int i = 0; i < setengahBlok; i++)
            {
                right[i] = text[setengahBlok + i];
            }

            //round
            for (int i = 6; i >= 0; i--)
            {
                byte[] temp = new byte[right.Length];
                //temp diisi dengan right
                right.CopyTo(temp, 0);

                //operasikan
                right = decryptround(left, right, roundkey[i]);
                left = temp;
            }

            //inverse permutasi
            byte[] result = new byte[panjangBlok];

            int iterator = 0;
            for (int i = 0; i < panjangBlok; i += 2)
            {
                result[i] = left[iterator];
                iterator++;
            }

            iterator = 0;
            for (int i = 1; i < panjangBlok; i += 2)
            {
                result[i] = right[iterator];
                iterator++;
            }

            return result;
        }

        private static byte[] encryptround(byte[] left, byte[] right, byte[] key)
        //satu putaran feistel untuk enkripsi
        {
            int setengahBlok = key.Length;
            byte[] innerfunctionresult = innerFunction.innerEnkrip(right, key);
            return generateTrueKey.XorNBitKey(left, innerfunctionresult, setengahBlok);
        }

        private static byte[] decryptround(byte[] left, byte[] right, byte[] key)
        //satu putaran feistel untuk dekripsi
        {
            int setengahBlok = key.Length;
            byte[] XORresult = generateTrueKey.XorNBitKey(left, right, setengahBlok);
            return innerFunction.innerDekrip(XORresult, key);
        }

        private static void generateroundkey(byte[] truekey)
        //membangkitkan kunci untuk setiap putaran
        //ada 7 putaran, kunci masing-masing putaran sepanjang 1/2 dari truekey
        {
            int setengahBlok = truekey.Length / 2;

            //kunci pertama adalah angka-angka pada setengah bagian pertama dari truekey
            roundkey[0] = new byte[setengahBlok];
            for (int i = 0; i < setengahBlok; i++)
            {
                roundkey[0][i] = truekey[i];
            }

            //kunci kedua adalah angka-angka pada setengah bagian terakhir dari truekey
            roundkey[1] = new byte[setengahBlok];
            for (int i = 0; i < setengahBlok; i++)
            {
                roundkey[1][i] = truekey[setengahBlok + i];
            }

            //kunci selanjutnya adalah hasil xor dari 2 kunci sebelumnya (kayak fibonaci)
            for (int i = 2; i < 7; i++)
            {
                roundkey[i] = generateTrueKey.XorNBitKey(roundkey[i - 2], roundkey[i - 1], setengahBlok);
            }
        }
    }
}
